/*
CpGears v1.0

Copyright (c) 2010 Yves Riel http://www.flash-factor.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package cpgears.movie {
	import cpgears.helpers.StringUtil;
	import cpgears.helpers.Version;
	import cpgears.log.ILogger;
	import cpgears.log.LogManager;
	import cpgears.movie.container.ContainerType;
	import cpgears.movie.MetaData;
	import cpgears.movie.slide.CPSlideAdapter;
	import cpgears.movie.slide.ISlide;
	import cpgears.movie.slide.NullSlide;
	import cpgears.movie.variables.CaptivateVariable;
	import cpgears.movie.variables.monitor.MonitoredVariableEvent;
	import cpgears.movie.variables.monitor.VariableMonitor;
	import cpgears.movie.widget.CPWidgetInfoAdapter;
	import cpgears.movie.widget.IWidget;
	import cpgears.WidgetBase;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	
	/**
	 * @private
	 * 
	 * Class adapting the Captivate movie parameters into a more structured data
	 * 
	 * @author Whyves
	 */
	public class CPMovieAdapter implements IMovie{
		
		private static var mLogger:ILogger;
		
		private var mMovieProperties:Object = null;
		private var mMovieHandle:* = null;
		private var mWidget:IWidget = null;
		private var mSlide:ISlide = null;
		private var mEventDispatcher:IEventDispatcher = null;
		private var mWidgetBase:WidgetBase = null;
		private var mVariableMonitor:VariableMonitor = null;
		
		/**
		 * Facade to the Captivate movie.
		 * 
		 * @param	movieHandle The Captivate Movie Handle
		 * @param	widget The instance of the widget
		 */
		public function CPMovieAdapter(movieHandle:Object, widget:WidgetBase) {
			if (widget == null) throw new ArgumentError("The 'widget' parameter cannot be null.");
			mLogger = LogManager.getLogger(this);
			mMovieHandle = movieHandle;
			mMovieProperties = movieHandle.getMovieProps();
			mEventDispatcher = mMovieProperties.eventDispatcher;
			mWidgetBase = widget;
		}
		
		/**
		 * @inheritDoc
		 */
		public function getCpVariable(variableName:String):* {
			var variableValue:* = null;
			try {
				variableValue = mMovieProperties.variablesHandle.cpGetValue(variableName);
			} catch (err:Error){
				mLogger.warn("Captivate variable '{0}' could not be found.", variableName);
			}
			return variableValue;
		}

		/**
		 * @inheritDoc
		 */
		public function setCpVariable(variableName:String, value:*):void {
			try {
				mMovieProperties.variablesHandle.cpEISetValue(variableName, value);
			} catch (err:Error){
				mLogger.warn("Captivate variable '{0}' could not be set.", variableName);
			}
		}
		
		/**
		 * @inheritDoc
		 */
		public function get contentWidth():Number {
			return mMovieProperties.contentWidth;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get contentHeight():Number {
			return mMovieProperties.contentHeight;
		}

		/**
		 * @inheritDoc
		 */
		public function get contentTop():Number {
			return getCpVariable(CaptivateVariable.CONTENT_TOP);
		}

		/**
		 * @inheritDoc
		 */
		public function get contentLeft():Number {
			return getCpVariable(CaptivateVariable.CONTENT_LEFT);
		}

		/**
		 * @inheritDoc
		 */
		public function gotoSlide(slideNumber:Number):void {
			setCpVariable(CaptivateVariable.GOTO_SLIDE, slideNumber);
		}
		
		/**
		 * @inheritDoc
		 */
		public function hasPlaybar():Boolean {
			return Boolean(getCpVariable(CaptivateVariable.HAS_PLAYBAR));
		}
		
		
		/**
		 * @inheritDoc
		 */
		public function get captivateVersion():Version {
			return new Version(getCpVariable("CaptivateVersion"));
		}
		
		/**
		 * @inheritDoc
		 */
		public function replaceVariables(text:String):String {
			return mMovieHandle.replaceVariables(text);
		}
		
		/**
		 * @inheritDoc
		 */
		public function get widget():IWidget {
			if (mWidget == null) mWidget = new CPWidgetInfoAdapter(mMovieHandle, mWidgetBase);
			return mWidget;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get slide():ISlide {
			if (mSlide == null) mSlide = (widget.containerType != ContainerType.MOVIE) ? new CPSlideAdapter(mMovieHandle, mWidgetBase) : new NullSlide();
			return mSlide;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get metadata():MetaData {
			return new MetaData(this);
		}
		
		/**
		 * @inheritDoc
		 */
		public function get systemData():SystemData {
			return new SystemData(this);
		}
		
		/**
		 * @inheritDoc
		 */
		public function monitorVariable(variableName:String):void {
			if (StringUtil.isNullOrEmpty(variableName)) {
				mLogger.warn("Trying to monitor a null or empty variable name. Nothing will be monitored.");
				return;
			}

			if (mVariableMonitor == null) {
				mVariableMonitor = new VariableMonitor(mMovieProperties.variablesHandle);
				mVariableMonitor.addEventListener(VariableMonitor.VARIABLE_CHANGED, onVariableChanged);
			}
			
			mVariableMonitor.addVariable(variableName);
		}
		
		public function unmonitorVariable(variableName:String):void {
			if (StringUtil.isNullOrEmpty(variableName)) {
				mLogger.warn("Trying to unmonitor a null or empty variable name. Nothing will be unmonitored.");
				return;
			}
			
			mVariableMonitor.removeVariable(variableName);
			
			if (mVariableMonitor.variablesCount == 0) {
				mVariableMonitor.removeEventListener(VariableMonitor.VARIABLE_CHANGED, onVariableChanged);
			}
		}
		
		/**
		 * @private
		 */
		private function onVariableChanged(event:MonitoredVariableEvent):void {
			dispatchEvent(new MonitoredVariableEvent(MovieEvent.VARIABLE_CHANGED, event.monitoredVariable));
		}

		/**
		 * @inheritDoc
		 */
		public function isPreview():Boolean {
			return Boolean(getCpVariable(CaptivateVariable.IS_PREVIEW));
		}

		/**
		 * @inheritDoc
		 */
		public function addEventListener (type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false) : void {
			mEventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}

		/**
		 * @inheritDoc
		 */
		public function dispatchEvent (event: Event) : Boolean {
			return mEventDispatcher.dispatchEvent(event);
		}

		/**
		 * @inheritDoc
		 */
		public function hasEventListener (type:String) : Boolean {
			return mEventDispatcher.hasEventListener(type);
		}

		/**
		 * @inheritDoc
		 */
		public function removeEventListener (type:String, listener:Function, useCapture:Boolean = false) : void {
			mEventDispatcher.removeEventListener(type, listener, useCapture);
		}

		/**
		 * @inheritDoc
		 */
		public function willTrigger (type:String) : Boolean {
			return mEventDispatcher.willTrigger(type);
		}
	}
}